package com.sky.aspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.ApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.StringUtils;
import reactor.core.publisher.Flux;

import java.lang.reflect.Method;

/**
 * 记录缓存名, 每周日自动清理缓存
 */
@Aspect
@Slf4j
public class CacheAspect implements Ordered {
	
	@Autowired
	private ApplicationContext applicationContext;
	
	@Pointcut("@annotation(org.springframework.cache.annotation.Cacheable)")
	public void cacheable() {
	}
	
	@Before("cacheable()")
	public void handleCacheable(JoinPoint joinPoint) {
		MethodSignature signature = (MethodSignature) joinPoint.getSignature();
		Method method = signature.getMethod();
		saveCacheName(method.getDeclaredAnnotation(Cacheable.class).cacheNames());
	}
	
	public void saveCacheName(String[] cacheNames) {
		Flux.fromArray(cacheNames)
				.filter(StringUtils::hasText)
				.doOnError(e -> log.warn("failed to saveCacheName: " + e.getMessage()))
				.subscribe(cacheName -> {
					HashOperations<String, String, String> opsForHash =
							applicationContext.getBean(StringRedisTemplate.class).opsForHash();
					opsForHash.putIfAbsent("__cacheName", cacheName, cacheName);
				});
	}
	
	@Override
	public int getOrder() {
		return -1;
	}
}